/**
 * Array.c
 * Implementation of Array.
 * @author: zt 2013-10-08
 */
#include "Array.h"
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>

#define PRIVATE static

struct Attr {
	int* data;
	int size;
	int capacity;	
};

PRIVATE int EnsureCapacity(Array* array)
{
	int* data;
	struct Attr* pattr = (struct Attr*)array->attr;
	//
	if(pattr->size < pattr->capacity)
		return TRUE;
	if(pattr->capacity > INT_MAX / 2)
		return FALSE;
	//
	data = (int*)realloc(pattr->data, (pattr->capacity << 1) * sizeof(int));
	assert(data != NULL);
	if(data != NULL) {
		pattr->data = data;
		pattr->capacity <<= 1;
		return TRUE;
	}
	//
	return FALSE;
}

PRIVATE int Init(Array* array, int initCapacity)
{
	struct Attr* pattr = NULL;
	if(array == NULL || initCapacity < 0)
		return FALSE;
		
	pattr = malloc(sizeof(struct Attr));
	if(pattr == NULL)
		return FALSE;
	
	pattr->data = (int*)malloc(initCapacity * sizeof(int));
	if(pattr->data == NULL)
		return FALSE;
	pattr->capacity = initCapacity;
	pattr->size = 0;
	array->attr = (void*)pattr;
	
	return TRUE;
}

PRIVATE void Destroy(Array* array)
{
	struct Attr* pattr = (struct Attr*)array->attr;
	if(array == NULL || array->attr == NULL)
		return ;
	if(pattr->data != NULL)
		free(pattr->data);
	free(pattr);
	array->attr = NULL;
	return ;
}

PRIVATE int Size(Array* array)
{
	assert(array != NULL);
	return ((struct Attr*)array->attr)->size;
}

PRIVATE	int Capacity(Array* array)
{
	assert(array != NULL);
	return ((struct Attr*)array->attr)->capacity;
}

PRIVATE void Push(Array* array,int item)
{
	struct Attr* pattr = (struct Attr*)array->attr;
	assert(array != NULL);
	if(EnsureCapacity(array) == FALSE) {
		fprintf(stderr, "Capacity beyond the range.");
		getchar();
		exit(ARRAYERROR_CapacityBeyondRange);
		return ;
	}
	pattr->data[pattr->size++] = item;
	return ;
}

PRIVATE	int Pop(Array* array)
{
	struct Attr* pattr = (struct Attr*)array->attr;
	assert(array != NULL && pattr->size > 0);
	return pattr->data[--pattr->size];
}

PRIVATE void Set(Array* array, int index, int item)
{
	struct Attr* pattr = (struct Attr*)array->attr;
	assert(array != NULL && index < pattr->size);
	pattr->data[index] = item;
}

PRIVATE int Get(Array* array, int index)
{
	struct Attr* pattr = (struct Attr*)array->attr;
	assert(array != NULL && index < pattr->size);
	return pattr->data[index];
}



Array* ArrayConstructor(Array* array)
{
	if(array == NULL)
		return NULL;
		
	array->Init = Init;
	array->Destroy = Destroy;
	
	array->Size = Size;
	array->Capacity = Capacity;
	
	array->Push = Push;
	array->Pop = Pop;
	array->Set = Set;
	array->Get = Get;
	
	return array;
}



